import hashlib
import json

from django.contrib.auth.hashers import make_password, check_password
from django_restql.fields import DynamicSerializerMethodField
from rest_framework import serializers
from rest_framework.decorators import action, permission_classes
from rest_framework.permissions import IsAuthenticated
from django.db import connection, models
from application import dispatch
from rest_framework.views import APIView
from dvadmin.system.models import Users, Role, Dept, ActivityRecord
from dvadmin.system.views.role import RoleSerializer
from dvadmin.utils.backends import logger
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.validator import CustomUniqueValidator
from dvadmin.utils.viewset import CustomModelViewSet
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView


def recursion(instance, parent, result):
    new_instance = getattr(instance, parent, None)
    res = []
    data = getattr(instance, result, None)
    if data:
        res.append(data)
    if new_instance:
        array = recursion(new_instance, parent, result)
        res += (array)
    return res


# class UserSerializer(CustomModelSerializer):
class UserSerializer(serializers.ModelSerializer):
    """
    User management-serializer
    """
    dept_name = serializers.CharField(source='dept.name', read_only=True)
    role_info = DynamicSerializerMethodField()
    permission_classes = []
    authentication_classes = []

    class Meta:
        model = Users
        read_only_fields = ["id"]
        exclude = ["password"]
        extra_kwargs = {
            "post": {"required": False},
        }

    def get_role_info(self, instance, parsed_query):
        roles = instance.role.all()
        # You can do what ever you want in here
        # `parsed_query` param is passed to BookSerializer to allow further querying
        serializer = RoleSerializer(
            roles,
            many=True,
            parsed_query=parsed_query
        )
        return serializer.data


class UsersInitSerializer(CustomModelSerializer):
    """
    Initialization to get information (used to generate the initial json file)
    """

    def save(self, **kwargs):
        instance = super().save(**kwargs)
        role_key = self.initial_data.get('role_key', [])
        role_ids = Role.objects.filter(key__in=role_key).values_list('id', flat=True)
        instance.role.set(role_ids)
        dept_key = self.initial_data.get('dept_key', None)
        dept_id = Dept.objects.filter(key=dept_key).first()
        instance.dept = dept_id
        instance.save()
        return instance

    class Meta:
        model = Users
        fields = ["username", "email", 'mobile', 'avatar', "name", 'gender', 'user_type', "dept", 'user_type',
                  'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'creator', 'dept_belong_id',
                  'password', 'last_login', 'is_superuser']
        read_only_fields = ['id']
        extra_kwargs = {
            'creator': {'write_only': True},
            'dept_belong_id': {'write_only': True}
        }


class UserCreateSerializer(CustomModelSerializer):
    """
    User addition-serializer
    """

    username = serializers.CharField(
        max_length=50,
        validators=[
            CustomUniqueValidator(queryset=Users.objects.all(), message="Account must be unique")
        ],
    )
    password = serializers.CharField(
        required=False,
    )

    def validate_password(self, value):
        """
        Verify password
        """
        password = self.initial_data.get("password")
        if password:
            return make_password(value)
        return value

    def save(self, **kwargs):
        data = super().save(**kwargs)
        data.dept_belong_id = data.dept_id
        data.save()
        data.post.set(self.initial_data.get("post", []))
        return data

    class Meta:
        model = Users
        fields = "__all__"
        read_only_fields = ["id"]
        extra_kwargs = {
            "post": {"required": False},
        }


class UserUpdateSerializer(CustomModelSerializer):
    """
    User modification-serializer
    """

    username = serializers.CharField(
        max_length=50,
        validators=[
            CustomUniqueValidator(queryset=Users.objects.all(), message="Account must be unique")
        ],
    )
    # password = serializers.CharField(required=False, allow_blank=True)
    mobile = serializers.CharField(
        max_length=50,
        validators=[
            CustomUniqueValidator(queryset=Users.objects.all(), message="Mobile number must be unique")
        ],
        allow_blank=True
    )

    def save(self, **kwargs):
        data = super().save(**kwargs)
        data.dept_belong_id = data.dept_id
        data.save()
        data.post.set(self.initial_data.get("post", []))
        return data

    class Meta:
        model = Users
        read_only_fields = ["id", "password"]
        fields = "__all__"
        extra_kwargs = {
            "post": {"required": False, "read_only": True},
        }


class UserInfoUpdateSerializer(CustomModelSerializer):
    """
    User modification-serializer
    """
    class Meta:
        model = Users
        fields = ['email', 'avatar', 'name', 'gender', 'mobile']
        extra_kwargs = {
            "email": {"required": False},
            "name": {"required": False},
            "gender": {"required": False},
            "avatar": {"required": False},
            "mobile": {"required": False},
        }

    def validate_mobile(self, value):
        """验证手机号"""
        if value:
            if Users.objects.exclude(id=self.instance.id).filter(mobile=value).exists():
                raise serializers.ValidationError("Mobile number must be unique")
        return value

    def update(self, instance, validated_data):
        logger.info(f"Updating user with data: {validated_data}")
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        return instance


class ExportUserProfileSerializer(CustomModelSerializer):
    """
    User export serializer
    """

    last_login = serializers.DateTimeField(
        format="%Y-%m-%d %H:%M:%S", required=False, read_only=True
    )
    is_active = serializers.SerializerMethodField(read_only=True)
    dept_name = serializers.CharField(source="dept.name", default="")
    dept_owner = serializers.CharField(source="dept.owner", default="")
    gender = serializers.CharField(source="get_gender_display", read_only=True)

    def get_is_active(self, instance):
        return "Enabled" if instance.is_active else "Disabled"

    class Meta:
        model = Users
        fields = (
            "username",
            "name",
            "email",
            "mobile",
            "gender",
            "is_active",
            "last_login",
            "dept_name",
            "dept_owner",
        )


class UserProfileImportSerializer(CustomModelSerializer):
    password = serializers.CharField(required=True, max_length=50, error_messages={"required": "Login password cannot be empty"})

    def save(self, **kwargs):
        data = super().save(**kwargs)
        password = hashlib.new(
            "md5", str(self.initial_data.get("password", "admin123456")).encode(encoding="UTF-8")
        ).hexdigest()
        data.set_password(password)
        data.save()
        return data

    class Meta:
        model = Users
        exclude = (
            "post",
            "user_permissions",
            "groups",
            "is_superuser",
            "date_joined",
        )


class UserViewSet(CustomModelViewSet):
    """
    User interface
    list: query
    create: add
    update: modify
    retrieve: single instance
    destroy: delete
    """

    queryset = Users.objects.exclude(is_superuser=1).all()
    serializer_class = UserSerializer
    create_serializer_class = UserCreateSerializer
    update_serializer_class = UserUpdateSerializer
    filter_fields = ["^name", "~username", "^mobile", "is_active", "dept", "user_type", "$dept__name"]
    # filter_fields = {
    #     "name": ["icontains"],
    #     "mobile": ["iregex"],
    #     "username": ["icontains"],
    #     "is_active": ["icontains"],
    #     "dept": ["exact"],
    #     "user_type": ["exact"],
    #     "dept__name": ["icontains"],
    # }
    search_fields = ["username", "name", "gender", "dept__name", "role__name"]
    # Export
    export_field_label = {
        "username": "Account",
        "name": "User name",
        "email": "Email",
        "mobile": "Mobile number",
        "gender": "User gender",
        "is_active": "Account status",
        "last_login": "Last login time",
        "dept_name": "Department name",
        "dept_owner": "Department owner",
    }
    export_serializer_class = ExportUserProfileSerializer
    # Import
    import_serializer_class = UserProfileImportSerializer
    import_field_dict = {
        "username": "Login account",
        "name": "User name",
        "email": "Email",
        "mobile": "Mobile number",
        "gender": {
            "title": "User gender",
            "choices": {
                "data": {"Unknown": 2, "Male": 1, "Female": 0},
            }
        },
        "is_active": {
            "title": "Account status",
            "choices": {
                "data": {"Enabled": True, "Disabled": False},
            }
        },
        "password": "Login password",
        "dept": {"title": "Department", "choices": {"queryset": Dept.objects.filter(status=True), "values_name": "name"}},
        "role": {"title": "Role", "choices": {"queryset": Role.objects.filter(status=True), "values_name": "name"}},
    }

    @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
    def user_info(self, request):
        """Get current user information"""
        user = request.user
        
        # Get user's activity statistics
        activity_stats = ActivityRecord.objects.filter(winners_user_id=user.id).aggregate(
            total_activities=models.Count('id'),
            lottery_count=models.Count('id', filter=models.Q(activity_type=2)),  # Raffle activity
        )
        
        # Get user's currency info
        currency_info = {
            'currency_num': getattr(user, 'currency_num', 0),
            'coins': getattr(user, 'currency_num', 0),  # If coins and currency_num are the same value
        }
        
        # Get participation stats
        participation_stats = {
            'join': ActivityRecord.objects.filter(winners_user_id=user.id).count(),
            'browse': getattr(user, 'browse_count', 0),  # If there is a browse record field
        }
        
        result = {
            "id": user.id,
            "username": user.username,
            "name": user.name,
            "mobile": user.mobile,
            "user_type": user.user_type,
            "gender": user.gender,
            "email": user.email,
            "avatar": user.avatar,
            "dept": user.dept_id,
            "is_superuser": user.is_superuser,
            "activities": activity_stats.get('total_activities', 0),
            "lottery": activity_stats.get('lottery_count', 0),
            "currency_num": currency_info['currency_num'],
            "coins": currency_info['coins'],
            "join": participation_stats['join'],
            "browse": participation_stats['browse'],
            "role": user.role.values_list('id', flat=True),
        }
        
        if hasattr(connection, 'tenant'):
            result['tenant_id'] = connection.tenant and connection.tenant.id
            result['tenant_name'] = connection.tenant and connection.tenant.name
        
        dept = getattr(user, 'dept', None)
        if dept:
            result['dept_info'] = {
                'dept_id': dept.id,
                'dept_name': dept.name
            }
        
        role = getattr(user, 'role', None)
        if role:
            result['role_info'] = role.values('id', 'name', 'key')
        
        return DetailResponse(data=result, msg="Successfully retrieved user information")

    @action(methods=["GET"], detail=True)
    def get_shop_info(self, request, pk):
        logger.info(f"User info retrieved for user ID: {request.user.id}")
        result = Users.objects.filter(id=request.user.id).values()
        return DetailResponse(data=result, msg="Successfully retrieved shop information")

    @action(methods=["PUT"], detail=False, permission_classes=[IsAuthenticated])
    def update_user_info(self, request):
        """Update current user information"""
        try:
            # 打印请求数据，用于调试
            logger.info(f"Update user info request data: {request.data}")
            
            # 检查请求数据是否为空
            if not request.data:
                return ErrorResponse(msg="Request data cannot be empty")
            
            serializer = UserInfoUpdateSerializer(request.user, data=request.data, partial=True)
            if serializer.is_valid():
                # 打印验证后的数据
                logger.info(f"Valid data: {serializer.validated_data}")
                
                # 确保至少有一个字段要更新
                if not serializer.validated_data:
                    return ErrorResponse(msg="No valid fields to update")
                    
                instance = serializer.save()
                # 打印保存后的实例数据
                logger.info(f"Updated user info: {instance.__dict__}")
                
                # 返回更新后的用户信息
                return DetailResponse(data={
                    'name': instance.name,
                    'email': instance.email,
                    'mobile': instance.mobile,
                    'gender': instance.gender,
                    'avatar': instance.avatar
                }, msg="Successfully updated")
            else:
                # 打印验证错误
                logger.error(f"Validation errors: {serializer.errors}")
                return ErrorResponse(msg="Invalid data", data=serializer.errors)
        except Exception as e:
            # 打印异常信息
            logger.error(f"Error updating user info: {str(e)}")
            return ErrorResponse(msg=f"Update failed: {str(e)}")

    @action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
    def change_password(self, request, *args, **kwargs):
        """Change password"""
        data = request.data
        old_pwd = data.get("oldPassword")
        new_pwd = data.get("newPassword")
        new_pwd2 = data.get("newPassword2")
        if old_pwd is None or new_pwd is None or new_pwd2 is None:
            return ErrorResponse(msg="Parameters cannot be empty")
        if new_pwd != new_pwd2:
            return ErrorResponse(msg="Passwords do not match")
        verify_password = check_password(old_pwd, self.request.user.password)
        if not verify_password:
            verify_password = check_password(hashlib.md5(old_pwd.encode(encoding='UTF-8')).hexdigest(), self.request.user.password)
        if verify_password:
            request.user.password = make_password(new_pwd)
            request.user.save()
            return DetailResponse(data=None, msg="Password changed successfully")
        else:
            return ErrorResponse(msg="Old password is incorrect")

    @action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
    def reset_to_default_password(self, request, *args, **kwargs):
        """Reset to default password"""
        instance = Users.objects.filter(id=kwargs.get("pk")).first()
        if instance:
            instance.set_password(dispatch.get_system_config_values("base.default_password"))
            instance.save()
            return DetailResponse(data=None, msg="Password reset successfully")
        else:
            return ErrorResponse(msg="User not found")

    @action(methods=["PUT"], detail=True)
    def reset_password(self, request, pk):
        """
        Reset password
        """
        instance = Users.objects.filter(id=pk).first()
        data = request.data
        new_pwd = data.get("newPassword")
        new_pwd2 = data.get("newPassword2")
        if instance:
            if new_pwd != new_pwd2:
                return ErrorResponse(msg="Passwords do not match")
            else:
                instance.password = make_password(new_pwd)
                instance.save()
                return DetailResponse(data=None, msg="Password changed successfully")
        else:
            return ErrorResponse(msg="User not found")

class AppRegisterView(APIView):

    permission_classes = []
    authentication_classes = []

    def post(self, request):

        users = Users.objects.filter(username=request.data['username'])

        if users.exists():
            return ErrorResponse(msg="Username already exists")

        Users.objects.create(
            user_type=request.data['userType'], 
            username=request.data['username'], 
            password=make_password(request.data['password']), 
            is_superuser=1
        )
        return DetailResponse(msg="Registration successful")
